﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Diagnostics;

namespace UIControls
{
    /// <summary>
    /// Will display the outputs of a PS rendering for a particular PS file.
    /// </summary>
    public partial class PSPane : UserControl
    {
        public PSPane()
        {
            InitializeComponent();
            renderedImages.SizeChanged += new EventHandler(renderedImages_SizeChanged);
        }

        WaitForRender waitPane = null;
        bool imageLoaded = false;
        RenderingErrorInfo errorPane = null;

        /// <summary>
        /// Put up the "rendering" pane. Make sure to lock so we don't get on each others feet!
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            ///
            /// Lock so that we know what is going on here!
            /// 

            lock (this)
            {
                if (!imageLoaded)
                {
                    renderedImages.Visible = false;
                    waitPane = new WaitForRender();
                    Height = waitPane.Height;
                    Controls.Add(waitPane);
                    waitPane.Dock = DockStyle.Fill;
                    waitPane.Visible = true;
                    waitPane.BringToFront();
                }
            }
        }

        /// <summary>
        /// Our sub-dude change size. We need to match it exactly.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void renderedImages_SizeChanged(object sender, EventArgs e)
        {
            Width = renderedImages.Width;
            Height = renderedImages.Height;
        }

        private FileInfo _psFile = null;

        /// <summary>
        /// Where the jpeg's are located.
        /// </summary>
        private DirectoryInfo TempFilesLocation = null;

        /// <summary>
        /// The DPI in the x-direction.
        /// </summary>
        private int DPIX = 0;

        /// <summary>
        /// Get/Set the file that will be rendered. Can only be set once.
        /// </summary>
        public FileInfo PSFile
        {
            get { return _psFile; }
            set
            {
                lock (this)
                {
                    if (_psFile != null)
                    {
                        throw new ArgumentException("PSFile can be set only once!");
                    }
                    _psFile = value;
                    if (_psFile != null && _psFile.Exists)
                    {
                        ///
                        /// Get the DPI before we get this started
                        /// 

                        Graphics g = this.CreateGraphics();
                        DPIX = (int)g.DpiX;
                        g.Dispose();

                        ThreadPool.QueueUserWorkItem((o) => Render());
                    }
                }
            }
        }

        private List<FileStream> imageStreams = new List<FileStream>();

        /// <summary>
        /// Run the render. We expect this to be running in
        /// a non-UI thread.
        /// </summary>
        /// <returns></returns>
        private void Render()
        {
            try
            {
                using (var itr = new Utilities.GSJpeggerAutoRotate(PSFile, DPIX))
                {
                    var files = from f in itr
                                select f;
                    foreach (var f in files)
                    {
                        FileStream fs = new FileStream(f.FullName, FileMode.Open, FileAccess.Read);
                        imageStreams.Add(fs);
                        Image img = Image.FromStream(fs);

                        PrepForFirstImage();

                        renderedImages.Add(img);
                    }

                    TempFilesLocation = itr.TempFileLocation;
                }
            }
            catch
            {
            }

            ///
            /// If nothing was rendered, put up an error
            ///

            if (renderedImages.Count == 0)
            {
                DisplayError();
            }
        }

        /// <summary>
        /// Make sure the wait-for-loading thing is done away with
        /// </summary>
        private void PrepForFirstImage()
        {
            if (InvokeRequired)
            {
                Invoke ((MethodInvoker) (() => PrepForFirstImage()));
            }
            else
            {
                if (!imageLoaded)
                {
                    lock (this)
                    {
                        if (waitPane != null)
                        {
                            RemoveWaitPane();
                        }
                        imageLoaded = true;
                        renderedImages.Visible = true;
                    }
                }
            }
        }

        /// <summary>
        /// Called to make he wait pane disappear. Can only be called on the UI thread.
        /// </summary>
        private void RemoveWaitPane()
        {
            Controls.Remove(waitPane);
            waitPane = null;
        }

        /// <summary>
        /// Called when there was an error rendering and nothing was displayed! We put up an error pane! Whee!
        /// Can be called from any thread.
        /// </summary>
        private void DisplayError()
        {
            if (InvokeRequired)
            {
                Invoke((MethodInvoker)(() => DisplayError()));
            }
            else
            {
                RemoveWaitPane();
                errorPane = new RenderingErrorInfo();
                Height = errorPane.Height;
                Controls.Add(errorPane);
                errorPane.Dock = DockStyle.Fill;
                errorPane.Visible = true;
                errorPane.BringToFront();
            }
        }

        /// <summary>
        /// When we are going away, make sure to clean up temp files, etc.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnHandleDestroyed(EventArgs e)
        {
            base.OnHandleDestroyed(e);

            foreach (var fs in imageStreams)
            {
                fs.Close();
            }

            TempFilesLocation.Refresh();
            if (TempFilesLocation != null && TempFilesLocation.Exists)
            {
                try
                {
                    TempFilesLocation.Delete(true);
                }
                catch
                {
                }
            }
        }
    }
}
